
//
// Copyright (c) 2008, the /*jupiter jazz*/ group
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the /*jupiter jazz*/ group nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY the /*jupiter jazz*/ group ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL the /*jupiter jazz*/ group BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

#ifndef CLASSLIB_TILE_H
#define CLASSLIB_TILE_H

// classlib headers.
#include "classlib/canvasproperties.h"

// Standard headers.
#include <cassert>
#include <cstddef>
#include <cstring>

namespace foundation
{

//
// A tile, as a 2D array of pixels.
//

class Tile
{
  public:
    // Construct a new tile. The content of the tile is left undefined.
    Tile(
        const PixelFormat   pixel_format,           // pixel format
        const size_t        width,                  // tile width, in pixels
        const size_t        height,                 // tile height, in pixels
        const size_t        channel_count,          // number of channels
        unsigned char*      storage = 0);           // if provided, use this memory for pixel storage

    // Copy constructor.
    Tile(const Tile&        rhs);

    // Destructor.
    virtual ~Tile();

    // Tile properties.
    PixelFormat get_pixel_format() const;
    size_t get_width() const;
    size_t get_height() const;
    size_t get_channel_count() const;               // number of channels in one pixel
    size_t get_pixel_count() const;                 // number of pixels
    size_t get_size() const;                        // size in bytes of the pixel array

    // Direct access to a given pixel.
    unsigned char* pixel(
        const size_t        x,
        const size_t        y);
    const unsigned char* pixel(
        const size_t        x,
        const size_t        y) const;

    // Structured write access to a given pixel, with automatic pixel format conversion.
    template <typename T>
    void set_pixel(
        const size_t        x,
        const size_t        y,
        const T&            val);                   // pixel value

    // Structured read access to a given pixel, with automatic pixel format conversion.
    template <typename T>
    void get_pixel(
        const size_t        x,
        const size_t        y,
        T&                  val) const;             // [out] pixel value

    // Set all pixels to a given color.
    template <typename T>
    void clear(const T&     val);                   // pixel value

  private:
    PixelFormat     m_pixel_format;                 // pixel format
    size_t          m_width;                        // tile width, in pixels
    size_t          m_height;                       // tile height, in pixels
    size_t          m_channel_count;                // number of channels per pixel
    size_t          m_pixel_count;                  // total number of pixels
    size_t          m_channel_size;                 // size in bytes of one channel
    size_t          m_pixel_size;                   // size in bytes of one pixel
    size_t          m_array_size;                   // size in bytes of the pixel array
    unsigned char*  m_pixel_array;                  // pixel array
    bool            m_own_storage;                  // does the tile own the memory used for pixel storage?

    // Forbid usage of assignment operator.
    const Tile& operator=(const Tile&);             // intentionally left unimplemented
};


//
// Tile class implementation.
//

// Tile properties.
inline PixelFormat Tile::get_pixel_format() const
{
    return m_pixel_format;
}
inline size_t Tile::get_width() const
{
    return m_width;
}
inline size_t Tile::get_height() const
{
    return m_height;
}
inline size_t Tile::get_channel_count() const
{
    return m_channel_count;
}
inline size_t Tile::get_pixel_count() const
{
    return m_width * m_height;
}
inline size_t Tile::get_size() const
{
    return m_array_size;
}

// Direct access to a given pixel.
inline unsigned char* Tile::pixel(
    const size_t    x,
    const size_t    y)
{
    assert(x < m_width);
    assert(y < m_height);
    const size_t index = (y * m_width + x) * m_pixel_size;
    assert(index < m_array_size);
    return m_pixel_array + index;
}
inline const unsigned char* Tile::pixel(
    const size_t    x,
    const size_t    y) const
{
    assert(x < m_width);
    assert(y < m_height);
    const size_t index = (y * m_width + x) * m_pixel_size;
    assert(index < m_array_size);
    return m_pixel_array + index;
}

}       // namespace foundation

#endif  // !CLASSLIB_TILE_H
